﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Xml;

namespace ProxyAppWeb
{
    public class S2SProxy: IS2SProxy
    {
        public string ExecuteGet(string getURL)
        {
            BO.URLParts urlParts = getSPHostReadyUrl(getURL);
            Uri hostWeb = new Uri(urlParts.TargetWebURL);
            var request = HttpContext.Current.Request;
            string accessToken = TokenHelper.GetS2SAccessTokenWithWindowsIdentity(hostWeb, request.LogonUserIdentity);
            Random rnd = new Random();
            string requestURL = urlParts.CleanURL;
            HttpWebRequest outboundRequest = (HttpWebRequest)HttpWebRequest.Create(requestURL);
            outboundRequest.Headers.Add("Authorization", "Bearer " + accessToken);
            foreach (var headerKey in request.Headers.AllKeys)
            {
                switch (headerKey)
                {
                    case "Connection":
                        // outboundRequest.Connection = request.Headers[headerKey];
                        break;
                    case "Host":
                        outboundRequest.Host = request.Headers[headerKey];
                        break;
                    case "User-Agent":
                        outboundRequest.UserAgent = request.Headers[headerKey];
                        break;
                    case "Referer":
                        outboundRequest.Referer = request.Headers[headerKey];
                        break;
                    case "Accept":
                        outboundRequest.Accept = request.Headers[headerKey];
                        break;
                    default:
                        // outboundRequest.Headers.Add(headerKey, request.Headers[headerKey]);
                        break;
                }
            }
            HttpWebResponse response = (HttpWebResponse)outboundRequest.GetResponse();
            StreamReader reader = new StreamReader(response.GetResponseStream());
            string toReturn = reader.ReadToEnd();
            return toReturn;
        }

        public string ExecutePost(string postURL, string postBody)
        {
            XmlNamespaceManager xmlnspm = new XmlNamespaceManager(new NameTable()); 
            xmlnspm.AddNamespace("d", "http://schemas.microsoft.com/ado/2007/08/dataservices");

            BO.URLParts urlParts = getSPHostReadyUrl(postURL);
            Uri hostWeb = new Uri(urlParts.TargetWebURL);
            var request = HttpContext.Current.Request;
            string accessToken = TokenHelper.GetS2SAccessTokenWithWindowsIdentity(hostWeb, request.LogonUserIdentity);

            HttpWebRequest contextinfoRequest =
                (HttpWebRequest)HttpWebRequest.Create(urlParts.TargetWebURL + "/_api/contextinfo");
            contextinfoRequest.Method = "POST";
            contextinfoRequest.ContentType = "text/xml;charset=utf-8";
            contextinfoRequest.ContentLength = 0;
            contextinfoRequest.Headers.Add("Authorization", "Bearer " + accessToken);

            HttpWebResponse contextinfoResponse = (HttpWebResponse)contextinfoRequest.GetResponse();
            StreamReader contextinfoReader = new StreamReader(contextinfoResponse.GetResponseStream(), System.Text.Encoding.UTF8);
            var formDigestXML = new XmlDocument();
            formDigestXML.LoadXml(contextinfoReader.ReadToEnd());
            var formDigestNode = formDigestXML.SelectSingleNode("//d:FormDigestValue", xmlnspm);
            string formDigest = formDigestNode.InnerXml;


            byte[] postBodyBytes = System.Text.Encoding.ASCII.GetBytes(postBody);

            string requestURL = urlParts.CleanURL;
            HttpWebRequest outboundRequest =
                (HttpWebRequest)HttpWebRequest.Create(requestURL);
            outboundRequest.Method = "POST";
            outboundRequest.ContentLength = postBody.Length;
            outboundRequest.ContentType = "application/json;odata=verbose";
            outboundRequest.Accept = "application/json;odata=verbose";
            outboundRequest.Headers.Add("Authorization", "Bearer " + accessToken);
            outboundRequest.Headers.Add("X-RequestDigest", formDigest);
            if (request.Headers.AllKeys.Any(k => k == "X-HTTP-Method"))
            {
                outboundRequest.Headers.Add("X-HTTP-Method", request.Headers["X-HTTP-Method"]);
                if (request.Headers["X-HTTP-Method"] == "DELETE") outboundRequest.ContentType = "text/plain;charset=UTF-8";
                if (request.Headers["X-HTTP-Method"] == "PUT") outboundRequest.ContentType = "text/plain;charset=UTF-8";
                
            }

            if (request.Headers.AllKeys.Any(k => k == "If-Match")) outboundRequest.Headers.Add("If-Match", request.Headers["If-Match"]);
            Stream listRequestStream = outboundRequest.GetRequestStream();
            listRequestStream.Write(postBodyBytes, 0, postBodyBytes.Length);
            listRequestStream.Close();

            HttpWebResponse response = (HttpWebResponse)outboundRequest.GetResponse();
            StreamReader reader = new StreamReader(response.GetResponseStream());
            string toReturn = reader.ReadToEnd();
            return toReturn;
        }

        private BO.URLParts getSPHostReadyUrl(string url)
        {
            if (url.StartsWith("/_api")) url = "http://dummy" + url;

            BO.URLParts toReturn = new BO.URLParts();
            url = HttpUtility.UrlDecode(url);
            var uri = new Uri(url);
            var myabspath = "";
            var targetVar = "";
            var nameValueCollection = HttpUtility.ParseQueryString(uri.Query);
            foreach (var segment in uri.Segments)
            {
                if (segment.ToLower().StartsWith("sp.appcontextsite(@"))
                {
                    targetVar = "@" + (segment.Split('@')[1]).Replace(")/", "");
                }
            }
                if (!String.IsNullOrEmpty(nameValueCollection[targetVar]))
                {
                    var hosturl = nameValueCollection[targetVar].Replace("'", "");
                toReturn.TargetWebURL = hosturl;

                var anotherSplit = url.Split(new string[] { "(" + targetVar + ")" }, StringSplitOptions.None);

                myabspath = hosturl + "/_api" + anotherSplit[1];
                toReturn.CleanURL = myabspath;
                return toReturn;
            }
            else return toReturn;


        }


    }
}